package com.itheima.d2_pool;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

//目标：掌握线程池的创建并且能执行Runnable任务
public class Demo01 {
    public static void main(String[] args) {
        /**
         * ThreadPoolExecutor构造器参数：
         *      核心线程数，
         *      最大线程数，
         *      临时线程最大存活时间，
         *      存活时间的单位，
         *      任务队列（等待的任务），
         *      创建线程的线程工厂（Executors.defaultThreadFactory()），
         *      拒绝策略（默认策略：new ThreadPoolExecutor.AbortPolicy()）
         *
         * ExecutorService的常用api：
         *      execute(Runnable command)：执行任务/命令，没有返回值，一般用来执行 Runnable 任务
         *      Future<T> submit(Callable<T> task)：执行任务，返回未来任务对象获取线程结果，一般拿来执行Callable任务
         *      shutdown()：等任务执行完毕后关闭线程池
         *      shutdownNow()：立刻关闭，停止正在执行的任务，并返回队列中未执行的任务
         *
         * 拒绝策略：
         *      ThreadPoolExecutor.AbortPolicy：丢弃任务并抛出RejectedExecutionException异常
         *      ThreadPoolExecutor.DiscardPolicy：丢弃任务，但是不抛出异常
         *      ThreadPoolExecutor.DiscardOldestPolicy：抛弃队列中等待最久的任务 然后把当前任务加入队列中
         *      ThreadPoolExecutor.CallerRunsPolicy：由主线程负责调用任务的run()方法从而绕过线程池直接执行
         */

        //需求：创建一个线程池对象，池子里有3个核心线程，最大线程6个，临时线程存活8秒。任务队列可以排队2个线程
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
                //1.1 核心线程
                3,
                //1.2 最大线程
                6,
                //1.3 临时线程存活时间数字
                8,
                //1.4 时间单位
                TimeUnit.SECONDS,
                //1.5 任务队列
                new ArrayBlockingQueue<>(2),
                //1.6 线程工厂
                Executors.defaultThreadFactory(),
                //1.7 拒绝策略
                new ThreadPoolExecutor.AbortPolicy()
                //new ThreadPoolExecutor.DiscardPolicy()
                //new ThreadPoolExecutor.DiscardOldestPolicy()
//                new ThreadPoolExecutor.CallerRunsPolicy()
        );

        //需求：利用for循环，并使用线程池分别执行3、5、6、8、9个任务，在任务中打印线程名字和任务数字
        //1.定义一个任务类MyRunnable，里面打印线程名字和任务数字

        //2.使用循环，不断的用线程池执行runnable任务
//        for (int i = 1; i <= 3; i++) {
//        for (int i = 1; i <= 5; i++) {
        //临时线程创建时机：核心线程都在忙，任务队列满了，此时过来新的线程！
//        for (int i = 1; i <= 6; i++) {
//        for (int i = 1; i <= 8; i++) {
        //拒绝任务的时机：核心和临时都在忙，队列也排满了，此时过来新的任务！
        for (int i = 1; i <= 9; i++) {
            pool.execute(new MyRunnable(i));
        }

        //3.关闭线程池
        pool.shutdown();
    }
}

